//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


namespace Shp.Runtime.DataModel.Sitka
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using Shp.Runtime.Common;
    using Shp.Runtime.Contract;
    using Shp.Runtime.DataModel.Sitka.Constants;
    using Shp.Runtime.Sitka.ServiceAgent;
    using Shp.Runtime.Sitka.ServiceAgent.Entities;
    
    public class AuthorizationDataModel
    {                        
        private IRepositoryFactory repositoryFactory;

        public AuthorizationDataModel(IRepositoryFactory factory)
        {
            repositoryFactory = factory;
        }

        public AuthorizationDataModel()
        {
            repositoryFactory = new GenericRepositoryFactory();
        }        

        public string[] GetActions(string tenantAlias, string[] credentials)
        {
            List<string> uriActions = new List<string>();
            SystemDataModel systemDataModel = new SystemDataModel(repositoryFactory);
            Guid tenantId = systemDataModel.GetTenantId(tenantAlias);
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                Guid[] actionIds = GetActionIds(tenantId, credentials, repository);
                foreach (Guid actionId in actionIds)
                {
                    GenericExtensibleEntity action = repository.GetById(actionId);
                    uriActions.Add(action.GetFieldValue(EntityFields.Uri));
                }
                IEnumerable<GenericExtensibleEntity> queryResult = repository.Search(String.Format(CultureInfo.InvariantCulture, Constants.SitkaAuthorizationQueries.GetSystemActions));
                foreach (GenericExtensibleEntity action in queryResult)
                {
                    uriActions.Add(action.GetFieldValue(EntityFields.Uri));
                }
            }
            return uriActions.ToArray();
        }

        public void UpdateCredentialPermission(string tenantAlias, string credential, Guid[] actionIdList)
        {
            SystemDataModel systemDataModel = new SystemDataModel(repositoryFactory);
            Guid tenantId = systemDataModel.GetTenantId(tenantAlias);

            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                IEnumerable<GenericExtensibleEntity> authorizations = repository.Search(String.Format(CultureInfo.InvariantCulture, Constants.SitkaAuthorizationQueries.GetAuthorizationsByCredential, credential, tenantId));
                foreach (GenericExtensibleEntity authorization in authorizations)
                {
                    repository.Delete(authorization.Id);
                }

                foreach (Guid action in actionIdList)
                {
                    AddAuthorization(tenantId, credential, action, repository);
                }
            }
        }

        public CredentialPermission[] GetCredentialPermissionList(string tenantAlias, string credential)
        {
            List<CredentialPermission> credentials = new List<CredentialPermission>();
            SystemDataModel systemDataModel = new SystemDataModel(repositoryFactory);
            Guid tenantId = systemDataModel.GetTenantId(tenantAlias);
            using (Repository<GenericExtensibleEntity> repository = repositoryFactory.MetadataRepository)
            {
                StringPair[] authorizations = GetAuthorizationIds(tenantId, credential, repository);
                foreach (StringPair authorization in authorizations)
                {
                    GenericExtensibleEntity action = repository.GetById(new Guid(authorization.Key));
                    if (action.GetFieldValue(EntityFields.IsSystem) == bool.FalseString)
                    {
                        CredentialPermission credentialPermission = new CredentialPermission();
                        credentialPermission.ActionId = authorization.Key;
                        credentialPermission.ActionUri = action.GetFieldValue(EntityFields.Uri);
                        credentialPermission.Description = action.GetFieldValue(EntityFields.Description);
                        credentialPermission.IsAuthorized = !String.IsNullOrEmpty(authorization.Value);
                        credentials.Add(credentialPermission);
                    }
                }
            }
            return credentials.ToArray();
        }

        private Guid[] GetActionIds(Guid tenantId, string[] credentials, Repository<GenericExtensibleEntity> repository)
        {
            List<Guid> actionIds = new List<Guid>();
            foreach (string credential in credentials)
            {
                IEnumerable<GenericExtensibleEntity> authorizations = repository.Search(String.Format(CultureInfo.InvariantCulture, Constants.SitkaAuthorizationQueries.GetAuthorizationsByCredential, credential, tenantId));
                foreach (GenericExtensibleEntity authorization in authorizations)
                {
                    actionIds.Add(new Guid(authorization.GetFieldValue(EntityFields.ActionId)));
                }
            }
            return actionIds.ToArray();
        }

        private StringPair[] GetAuthorizationIds(Guid tenantId, string credential, Repository<GenericExtensibleEntity> repository)
        {
            List<StringPair> authorizationsList = new List<StringPair>();
            IEnumerable<GenericExtensibleEntity> authorizations = repository.Search(String.Format(CultureInfo.InvariantCulture, Constants.SitkaAuthorizationQueries.GetAuthorizationsByCredential, credential, tenantId));
            foreach (GenericExtensibleEntity authorization in authorizations)
            {
                authorizationsList.Add(new StringPair(authorization.GetFieldValue(EntityFields.ActionId), authorization.Id.ToString()));
            }
            return authorizationsList.ToArray();
        }

        private void AddAuthorization(Guid tenantId, string credential, Guid actionId, Repository<GenericExtensibleEntity> repository)
        {
            GenericExtensibleEntity authorization = new GenericExtensibleEntity(EntityKinds.Authorization, Guid.NewGuid());
            authorization.Fields.Add(new Field(EntityFields.TenantId, tenantId.ToString()));
            authorization.Fields.Add(new Field(EntityFields.ActionId, actionId.ToString()));
            authorization.Fields.Add(new Field(EntityFields.Credential, credential));

            repository.Insert(authorization);
        }
    }
}
